#include "Nano100Series.h"
#include "UsbTransfer.h"
#include "HmdCmd.h"
#include "EventQueue.h"

static uint32_t u32TxSize2 = 0;
static uint8_t  u8TxBuf2[64];

static uint32_t u32RxSize3 = 0;
static uint8_t  u8RxBuf3[64];

static int epCount[8] = {0};


/*--------------------------------------------------------------------------*/
void USBD_IRQHandler(void)
{
	int i;
    uint32_t u32IntSts = USBD_GET_INT_FLAG();
    uint32_t u32State = USBD_GET_BUS_STATE();

	for (i = 0; i < 8; i++) {
		if (u32IntSts & (1UL << (16 + i))) {
			epCount[i]++;
		}
	}
	//------------------------------------------------------------------
    if (u32IntSts & USBD_INTSTS_FLDET) {
        // Floating detect
        USBD_CLR_INT_FLAG(USBD_INTSTS_FLDET);

        if (USBD_IS_ATTACHED()) {
            /* USB Plug In */
            USBD_ENABLE_USB();
        } else {
            /* USB Un-plug */
            USBD_DISABLE_USB();
        }
    }

	//------------------------------------------------------------------
    if (u32IntSts & USBD_INTSTS_BUS) {
        /* Clear event flag */
        USBD_CLR_INT_FLAG(USBD_INTSTS_BUS);

        if (u32State & USBD_STATE_USBRST) {
            /* Bus reset */
            USBD_ENABLE_USB();
            USBD_SwReset();
        }
        if (u32State & USBD_STATE_SUSPEND) {
            /* Enable USB but disable PHY */
            USBD_DISABLE_PHY();
        }
        if (u32State & USBD_STATE_RESUME) {
            /* Enable USB and enable PHY */
            USBD_ENABLE_USB();
        }
    }

	//------------------------------------------------------------------
    if (u32IntSts & USBD_INTSTS_USB) {
        // USB event
        if (u32IntSts & USBD_INTSTS_SETUP) {
            // Setup packet
            /* Clear event flag */
            USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP);

            /* Clear the data IN/OUT ready flag of control end-points */
            USBD_STOP_TRANSACTION(EP0);
            USBD_STOP_TRANSACTION(EP1);

            USBD_ProcessSetupPacket();
        }

        // EP events
        if (u32IntSts & USBD_INTSTS_EP0) {
            /* Clear event flag */
            USBD_CLR_INT_FLAG(USBD_INTSTS_EP0);

            // control IN
            USBD_CtrlIn();
        }

        if (u32IntSts & USBD_INTSTS_EP1) {
            /* Clear event flag */
            USBD_CLR_INT_FLAG(USBD_INTSTS_EP1);

            // control OUT
            USBD_CtrlOut();
        }
    }
    /* clear unknown event */
    USBD_CLR_INT_FLAG(u32IntSts);
}

void UsbClassRequest(void)
{
    uint8_t buf[8];

    USBD_GetSetupPacket(buf);
}

static void UsbInitInterface(void)
{
	/* EP2 ==> bulk IN endpoint, address 1 */
    USBD_CONFIG_EP(EP2, USBD_CFG_EPMODE_IN | 1);
    /* Buffer offset for EP2 */
    USBD_SET_EP_BUF_ADDR(EP2, EP2_BUF_BASE);
	USBD_SET_PAYLOAD_LEN(EP2, 0);

    /* EP3 ==> bulk OUT endpoint, address 1 */
    USBD_CONFIG_EP(EP3, USBD_CFG_EPMODE_OUT | 1);
    /* Buffer offset for EP3 */
    USBD_SET_EP_BUF_ADDR(EP3, EP3_BUF_BASE);
	USBD_SET_PAYLOAD_LEN(EP3, EP3_MAX_PKT_SIZE);
}

void UsbTransferInit(void)
{
	USBD_Open(&gsInfo, UsbClassRequest, NULL);

 	/* Init setup packet buffer */
    /* Buffer for setup packet -> [0 ~ 0x7] */
    USBD->BUFSEG = SETUP_BUF_BASE;

    /*****************************************************/
    /* EP0 ==> control IN endpoint, address 0 */
    USBD_CONFIG_EP(EP0, USBD_CFG_CSTALL | USBD_CFG_EPMODE_IN | 0);
    /* Buffer range for EP0 */
    USBD_SET_EP_BUF_ADDR(EP0, EP0_BUF_BASE);

    /* EP1 ==> control OUT endpoint, address 0 */
    USBD_CONFIG_EP(EP1, USBD_CFG_CSTALL | USBD_CFG_EPMODE_OUT | 0);
    /* Buffer range for EP1 */
    USBD_SET_EP_BUF_ADDR(EP1, EP1_BUF_BASE);

    /*****************************************************/
	UsbInitInterface();

	NVIC_EnableIRQ(USBD_IRQn);
}

void UsbTransferStart(void)
{
	USBD_Start();
}

void UsbTransferHandleEvent(void)
{
	uint32_t u32EpStat;

	static uint32_t u32Ep3StatOld = 0;
	uint32_t u32Ep3StatNew;

	u32EpStat = (uint32_t)(USBD->EPSTS);

	u32Ep3StatNew = u32EpStat & USBD_EPSTS_EPSTS3_Msk;
	if (u32Ep3StatNew != u32Ep3StatOld) {
		u32Ep3StatOld = u32Ep3StatNew;
		if ((u32Ep3StatNew == (0x02 << USBD_EPSTS_EPSTS3_Pos))
			|| (u32Ep3StatNew == (0x06 << USBD_EPSTS_EPSTS3_Pos)))
		{
			u32RxSize3 = USBD_GET_PAYLOAD_LEN(EP3);
			USBD_MemCopy(u8RxBuf3, (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP3)), u32RxSize3);
			HmdDispRspXfer((uint8_t *)u8RxBuf3, u32RxSize3, u8TxBuf2, sizeof(u8TxBuf2), &u32TxSize2);
			USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP2)), u8TxBuf2, u32TxSize2);
			USBD_SET_PAYLOAD_LEN(EP2, u32TxSize2);

			u32RxSize3 = 0;
			USBD_SET_PAYLOAD_LEN(EP3, EP3_MAX_PKT_SIZE);
			USBD_CLR_INT_FLAG(USBD_INTSTS_EP3);
		}
	}
}
